/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package exclusionmutua;

import java.io.Serializable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import net.jxta.protocol.PipeAdvertisement;


/**
 *
 * @author Eduardo
 */
public class Token implements Serializable{

    private static final long serialVersionUID = 2266080225126394L;

    /**El número de secuencia del nodo es un dato importante que es
     * diferente al manejado en el token pues que son los mensajes que ha enviado y recibido entre
     * dos nodos es por eso que lo adicione.
     */
     private int numeroSecuenciaNodo;

    /**Todo mensaje que es transmitido por la rede debe tener un color
     * Necesito este dato para manejar el estado global del sistema.
     */
     private String color;

    /**
     * Peer que es responsable de la gestión del archivo. Es usado para la descarga del archivo una
     * vez se tiene el token.
     */
    private PipeAdvertisement propietarioDescarga;

    /**
     * Peer que es responsable de la gestión del archivo. Es usado para la subida del archivo una vez
     * se terminó de utilizar el token.
     */
    private PipeAdvertisement pripietarioSubida;

    /**El idDocumento al cual esta asociado este token, esto va a permitir identificarlo
     * cuado se reciba un mensaje.
     */
    private String idDocumento;

    /**Guarda los números de secuencia que se han ejecutado recientemente*/
    private transient Map<PipeAdvertisement,Integer> LN = new HashMap<PipeAdvertisement, Integer>(ExclusionMutua.N);

    /*Guarda el id de los documentos que desean ingresar a la SC**/
    private transient Queue<PipeAdvertisement> Q = new LinkedList<PipeAdvertisement>();

    /**
     *
     * @param idDocumento Id del documento al que pertenece este token.
     * @param pipePropDescarga Pipe utilizado para la descarga del documento.
     * @param pipePropSubida Pipe utilizado para la subida del documento una vez haya sido liberado.
     */
    public Token(String idDocumento, PipeAdvertisement pipePropDescarga, PipeAdvertisement pipePropSubida) {
        this.idDocumento = idDocumento;
        this.propietarioDescarga = pipePropDescarga;
        this.pripietarioSubida = pipePropSubida;
    }

    public PipeAdvertisement getPropietarioDescarga() {
        return propietarioDescarga;
    }

    public PipeAdvertisement getPropietarioSubida(){
        return pripietarioSubida;
    }

    public void addSolicitante(PipeAdvertisement peer){
        if(peer == null)
            throw new NullPointerException("No se puede aniadir elementos nulos a Q");
        Q.offer(peer);
    }

    public PipeAdvertisement removeSolicitante(){
        return Q.poll();
    }

    public void setLNSequenceNumber(PipeAdvertisement peer, Integer seqNumb){
        LN.put(peer, seqNumb);
    }

    public Integer getLNSquenceNumber(PipeAdvertisement peer){
        return LN.get(peer);
    }

    /**
     * Devuelve los peers que tiene conocimiento el token, basado en su vector LN.
     *
     * @return Los peers guardados en el vector RN.
     */
    public Set<PipeAdvertisement> getLNPeerIDs(){
        return LN.keySet();
    }

    public Set<PipeAdvertisement> getNoEstanEnCola(){
        List<PipeAdvertisement> copyPeers = new LinkedList<PipeAdvertisement>(LN.keySet());
        copyPeers.removeAll(Arrays.asList(Q.toArray()));
        return new HashSet<PipeAdvertisement>(copyPeers);
    }

    public String getIdDocumento(){
        return idDocumento;
    }

    public Queue getCola(){
        return Q;
    }

    /**
     * @return the color
     */
    public String getColor() {
        return color;
    }

    /**
     * @param color the color to set
     */
    public void setColor(String color) {
        this.color = color;
    }

    /**
     * @return the numeroSecuenciaNodo
     */
    public int getNumeroSecuenciaNodo() {
        return numeroSecuenciaNodo;
    }

    /**
     * @param numeroSecuenciaNodo the numeroSecuenciaNodo to set
     */
    public void setNumeroSecuenciaNodo(int numeroSecuenciaNodo) {
        this.numeroSecuenciaNodo = numeroSecuenciaNodo;
    }

    @Override
    public boolean equals(Object obj) {
        //if (this == obj) return true;
        if (!(obj instanceof Token)) return false;
        Token token = (Token)obj;
        boolean idB = token.getIdDocumento().equals(this.getIdDocumento());
        boolean LNB = token.LN.equals(this.LN);
        boolean QB = token.Q.equals(this.Q);
        return  idB &&
                LNB &&
                QB;
    }

    public Token getCopy(){
        Token other = null;
        other = new Token(idDocumento, propietarioDescarga, pripietarioSubida);
        for(PipeAdvertisement pipe : this.getLNPeerIDs()){
            other.setLNSequenceNumber(pipe, this.getLNSquenceNumber(pipe));
        }
        for(Iterator<PipeAdvertisement> it = this.getCola().iterator(); it.hasNext();){
            other.addSolicitante(it.next());
        }
        return other;
    }

}
